#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
/*模拟实现string类，并完成测试*/
namespace fym
{
    class string
    {
        friend ostream& operator<<(ostream& out, const string& s);
        friend istream& operator>>(istream& in, string& s);
    public:
        // 反向迭代器暂不实现
        typedef char* iterator; // 迭代器
        typedef const char* const_iterator;
        iterator begin()
        {
            return _str;
        }
        iterator end()
        {
            return _str + _size;
        }
        const_iterator begin() const
        {
            return _str;
        }
        const_iterator end() const
        {
            return _str + _size;
        }

        // 短小且频繁调用的函数，可以直接定义在类里面，默认内联inline
        string(const char* str = "")
        {
            _size = strlen(str);
            // _capacity不包含\0
            _capacity = _size;
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }
        void swap(string& s)
        {
            // 此处自己额外实现swap是考虑到了深拷贝的问题
            // 交换char*, size_t等内置类型时，在C++11之前算法库实现的swap模板生成的函数效果还行
            // 但C++11之前实现的swap模板生成的函数是通过创建第三个临时对象来实现交换，遇到深拷贝的情况下有不少消耗
            // C++11后在std库全局专门为string实例化实现了一个swap函数---std::swap(string) void swap(string &x, string &y);
            std::swap(_str, s._str);
            std::swap(_size, s._size);
            std::swap(_capacity, s._capacity);
        }
        string(const string& s)
        {
            //// 传统写法
            //_str = new char[s._capacity + 1];
            //strcpy(_str, s._str);
            //_size = s._size;
            //_capacity = s._capacity;
            
            // 现代写法
            // 即通过默认构造创建一个临时的tmp对象，tmp与s完全一致，可以全部交换给需要的string对象
            string tmp(s._str);
            swap(tmp);
        }
        string& operator=(const string& s)
        {
            // 检查自己给自己赋值的情况
            if (this != &s)
            {
                //// 传统写法
                //delete[] _str;
                //_str = new char[s._capacity + 1];
                //strcpy(_str, s._str);
                //_size = s._size;
                //_capacity = s._capacity;

                // 现代写法
                // 在赋值=中实现比在拷贝构造中实现还额外多一个好处
                // 拷贝构造的*this是未初始化的string对象，但赋值的*this对象可能存在资源
                // 交换后*this中的资源都到了tmp中，tmp出了函数作用域即销毁，自动调用析构函数清理资源，省了传统写法中delete的功夫
                string tmp(s._str);
                swap(tmp);
            }
            return *this;
        }
        ~string()
        {
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }
        
        const char* c_str() const
        {
            return _str;
        }
        size_t size() const
        {
            return _size;
        }
        size_t capacity() const
        {
            return _capacity;
        }
        void clear()
        {
            _str[0] = '\0';
            _size = 0;
        }
        bool empty() const
        {
            return _size == 0;
        }
        
        char& operator[](size_t index)
        {
            assert(index < _size);
            return _str[index];
        }
        const char& operator[](size_t index) const
        {
            assert(index < _size);
            return _str[index];
        }

        void reserve(size_t n);
        void push_back(char c);
        void append(const char* str);
        string& operator+=(char c);
        string& operator+=(const char* str);

        string& insert(size_t pos, char c);
        string& insert(size_t pos, const char* str);
        string& erase(size_t pos, size_t len = npos);
        size_t find(char c, size_t pos = 0) const;
        size_t find(const char* s, size_t pos = 0) const;
        string substr(size_t pos = 0, size_t len = npos) const;
        void resize(size_t n, char c = '\0');
    private:
        char* _str;
        size_t _size;
        size_t _capacity;

        // static const整型类型的变量可以在此处直接声明且定义
        // 如static const size_t npos = -1; // 不建议这样写，尽量按照规定，此处仅声明，在初始化列表定义
        // double等不行，整型可以，如：bool, char, short, int, long, longlong, size_t等
        // 该特点可以实现以下写法：
        // static const size_t N = 10;
        // int buff[N];
        static const size_t npos;
    };
    bool operator<(const string& s1, const string& s2);
    bool operator<=(const string& s1, const string& s2);
    bool operator>(const string& s1, const string& s2);
    bool operator>=(const string& s1, const string& s2);
    bool operator==(const string& s1, const string& s2);
    bool operator!=(const string& s1, const string& s2);

    ostream& operator<<(ostream& out, const string& s);
    istream& operator>>(istream& in, string& s);
};